<?php if (!defined('PmWiki')) exit();
/*  Copyright 2006 Patrick R. Michaud (pmichaud@pobox.com)
    This file is abcmusic.php; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published
    by the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.  

    This script converts music files in "abc notation" into
    PostScript scores, gif images, and midi files.  Once
    configured (see below), this script enables markup
    of the form:

        (:music:)
        ...abc notation here...
        (:musicend:)

    Configuration:

    Depending on the outputs you wish to produce, your
    system will also need some or all of the following 
    external commands:

        abcm2ps     - converts abc notation to postscript
        gs         - Ghostscript
        ppmtogif   - Convert .ppm files to .gif
        abc2midi   - converts abc notation to .mid file

    The basic format for configuring this script is:

        $ABCProgs['abcm2ps'] = '/path/to/abcm2ps';
        $ABCProgs['abc2midi'] = '/path/to/abc2midi';
        include_once("cookbook/abcmusic.php");

    If the "gs" and "ppmtogif" utilities aren't in PHP's
    executable path by default, you will also want to set 
    appropriate values for $ABCProgs['gs'] and 
    $ABCProgs['ppmtogif'].

    The options passed to each program are also controlled
    by the $ABCPSCmdFmt, $ABCGifCmdFmt, and $ABCMidiCmdFmt
    variables, so those can be set in addition to (or in
    lieu of) the $ABCProgs variables above.

    Lastly, the script uses the variables $PubCacheDir
    and $PubCacheUrl to determine where to place temporary
    files and how to reach them by url.
*/

SDV($RecipeInfo['AbcMusic']['Version'], '2006-04-03');

## These are the external programs used for various aspects
## of converting .abc files.  Many sites will need to configure
## these parameters with absolute paths to the external programs.
SDVA($ABCProgs, array(
  'abcm2ps' => 'abcm2ps',
  'gs' => 'gs',
  'ppmtogif' => 'pnmcrop | ppmtogif',
  'abc2midi' => ''));

SDV($PubCacheDir,"pub/cache");
SDV($PubCacheUrl,"$PubDirUrl/cache");

## command to create .ps file
if ($ABCProgs['abcm2ps'])
  SDV($ABCPSCmdFmt, "{$ABCProgs['abcm2ps']} -O\$ABCFile.ps \$ABCFile.abc");

## command to create .gif file
if ($ABCProgs['gs'] && $ABCProgs['ppmtogif']) {
  SDV($ABCGifCmdFmt, "{$ABCProgs['gs']} -sDEVICE=ppmraw -sOutputFile=- -q -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -r96x96 \$ABCFile.ps | {$ABCProgs['ppmtogif']} >\$ABCFile.gif");
}

## command to create .mid file
if ($ABCProgs['abc2midi']) 
  SDV($ABCMidiCmdFmt, "{$ABCProgs['abc2midi']} \$ABCFile.abc -o \$ABCFile.mid");

## (:music:) markup
Markup('music', 'fulltext',
  '/\\(:music:\\)(.*?)\\(:musicend:\\)/eis',
  "Keep(AbcMusic(\$pagename, PSS('$1')))");


## This is the function that does all of the work.  :-)
## It just creates a suitable basename for the music files,
## calls each of the external programs to produce the corresponding
## output, and returns an  HTML string with links to the
## appropriate files.

function AbcMusic($pagename, $text) {
  global $FmtV, $PubCacheDir, $PubCacheUrl, $ABCProgs,
    $ABCPSCmdFmt, $ABCGifCmdFmt, $ABCMidiCmdFmt;
  $text = trim($text);
  $text = str_replace(array('&lt;', '&gt;', '&amp;'), array('<', '>', '&'),
                      $text);

  ## build a suitable filename from the music title (T:)
  if (preg_match('/^T:(.*)/m', $text, $match)) {
    $abctitle = $match[1];
    $abcname = preg_replace('/\\s+/', '_', $abctitle);
    $abcname = preg_replace('/\\W+/', '', $abcname);
    $abcname .= '_' . substr(md5($text), 0, 6);
  } else $abcname = md5($text);
  $abcfile = "$PubCacheDir/$abcname";
  $FmtV['$ABCName'] = $abcname;
  $FmtV['$ABCFile'] = $abcfile;

  ## Create the cache directory to hold the files
  mkdirp($PubCacheDir); fixperms($PubCacheDir);

  ## Create the "abc" file
  if (!file_exists("$abcfile.abc")) {
    $fp = fopen("$abcfile.abc", "w");
    if ($fp) { fputs($fp, "$text\n"); fclose($fp); }
    else return "abcmusic failed to create $abcfile.abc\n";
  }

  ## Create the "ps" file
  if (!file_exists("$abcfile.ps")) {
    $pscmd = FmtPageName($ABCPSCmdFmt, $pagename);
    if (system($pscmd) === false) 
      return "abcmusic failed to create $abcfile.ps\n";
  }

  ## Create the image file
  if (!file_exists("$abcfile.gif")) {
    $gifcmd = FmtPageName($ABCGifCmdFmt, $pagename);
    if (system($gifcmd) === false)
      return "abcmusic failed to create $abcfile.gif\n";
  }

  ## Create the midi file
  if ($ABCMidiCmdFmt && !file_exists("$abcfile.mid")) {
    $midicmd = FmtPageName($ABCMidiCmdFmt, $pagename);
    system($midicmd);
  }
    
  ## Return the image and output
  $out = "<div class='abcmusic'>";
  if (file_exists("$abcfile.gif"))
    $out .= "<img class='abcmusic' src='$PubCacheUrl/$abcname.gif' 
               alt='$abctitle' /><br />";
  if (file_exists("$abcfile.abc"))
    $out .= " <a href='$PubCacheUrl/$abcname.abc'>abc</a>";
  if (file_exists("$abcfile.ps"))
    $out .= " <a href='$PubCacheUrl/$abcname.ps'>ps</a>";
  if (file_exists("$abcfile.mid"))
    $out .= " <a href='$PubCacheUrl/$abcname.mid'>midi</a>";
  $out .= "</div>";
  return $out;
}

